#
# Copyright 2009 Jeffrey Palm
#

require 'util'
require 'library'
require 'track'

# An XML-based library is rooted at an ITunes Music Library.
class XmlBasedLibrary < Library

  attr_reader   :xml

  def initialize(xml)
    @xml = xml
  end
  
  def find_track(info)
    find_track_using_xml info
  end

  def find_info(track_id)
    find_info_using_xml track_id
  end

  private

  def find_info_using_xml(track_id)

    note 'Finding track info for ' + track_id.to_s

    the_track_id = nil
    name         = nil
    artist       = nil
    album        = nil

    lines = open(@xml).read.split /\n/
    lines.each do |line|
      
      # <key>Track ID</key><integer>1141</integer>
      if not the_track_id
        line.scan /<key>Track ID<\/key><integer>(\d+)<\/integer>/ do |res|
          the_track_id = res[0].to_i
          the_track_id = nil if the_track_id != track_id
        end
      end
      
      # <key>Artist</key><string>Sage Francis</string>
      if not artist
        line.scan /<key>Artist<\/key><string>([^<]+)<\/string>/ do |res|
          artist = res[0]
        end
      end

      # <key>Name</key><string>Hoofprints In the Sand</string>
      if not name
        line.scan /<key>Name<\/key><string>([^<]+)<\/string>/ do |res|
          name = res[0]
        end
      end
      
      # <key>Album</key><string>Human the Death Dance</string>
      if not album
        line.scan /<key>Album<\/key><string>([^<]+)<\/string>/ do |res|
          album = res[0]
        end
      end
      
      if the_track_id and name and artist and album

        puts [the_track_id,name,artist,album].join(',')

        if the_track_id == track_id
          info = {
            'track_id' => the_track_id,
            'artist'   => artist,
            'album'    => album,
            'track'    => name
          }
          return info
        else
          the_track_id = nil
          artist       = nil
          album        = nil
          name         = nil
        end

      end
    end
    return nil
  end

  # Take an itunes-like music library and finds a track for the info
  def find_track_using_xml(info)
    
    note 'Find track info:'
    note info_to_string info
    
    # Right now we only care about macs and iphones
    if not File.exist? @xml
      note 'Couldn\'t find itunes library at: ' + @xml
      return nil
    end
    
    lines = open(@xml).read.split /\n/
    
    # This is the actual track we're looking for, but, as you'll see,
    # we're cut some corners or matching an exact track
    note 'Looking for:'
    note ' artist : ' + info['artist'].to_s
    note ' album  : ' + info[ 'album'].to_s
    note ' track  : ' + info[ 'track'].to_s
    
    track_id = nil
    name     = nil
    artist   = nil
    album    = nil
    
    # Because it's easier we'll remove all quote from the song and
    # from the strings in the xml.  Create a new, imutable hash,
    # containing none of this nasty stuff.
    new_info = {}
    info.each do |k,v|
      next if not k # shouldn't happen
      next if not v # ok if it happens
      new_info[k] = remove_nasty_stuff v
    end
    info = new_info
    
    lines.each do |line|
      
      # <key>Track ID</key><integer>1141</integer>
      if not track_id
        line.scan /<key>Track ID<\/key><integer>(\d+)<\/integer>/ do |res|
          track_id = res[0]
        end
      end
      
      # <key>Artist</key><string>Sage Francis</string>
      if not artist
        line.scan /<key>Artist<\/key><string>([^<]+)<\/string>/ do |res|
          artist = res[0]
        end
      end
      # <key>Name</key><string>Hoofprints In the Sand</string>
      if not name
        line.scan /<key>Name<\/key><string>([^<]+)<\/string>/ do |res|
          name = res[0]
        end
      end

      # <key>Album</key><string>Human the Death Dance</string>
      if not album
        line.scan /<key>Album<\/key><string>([^<]+)<\/string>/ do |res|
          album = res[0]
        end
      end

      if track_id and name and artist and album
        
        # Do an easy compare, that is...  
        #  - if we find an artist on this device, but none on the
        #    other, use that artist
        #  - if we find an artist and album on this device, but an
        #    artist not but album on the other, use that artist
        #  - if we find an artist and album and track on the other
        #    device, but only an artist and album on this, use this
        #    track
        if ( compare_leniently(info['artist']  , artist) &&
             compare_leniently(info['album']   , album ) &&
             compare_leniently(info['track']    , name )   )
          return Track.new name,artist,album,track_id
        end
        track_id  = nil
        name      = nil
        artist    = nil
        album     = nil
      end
    end
    return nil
  end

end
